package com.tensquare.user.service;

import java.util.*;
import java.util.concurrent.TimeUnit;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.Selection;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;

import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import org.springframework.transaction.annotation.Transactional;
import util.IdWorker;

import com.tensquare.user.dao.UserDao;
import com.tensquare.user.pojo.User;

/**
 * 服务层
 *
 * @author Administrator
 */
@Service
public class UserService {

    @Autowired
    private UserDao userDao;

    @Autowired
    private IdWorker idWorker;

    @Value("${spring.redis.expiration-time}")
    private Integer expirationTime;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private BCryptPasswordEncoder encoder;

    /**
     * 更新关注数
     *
     * @param userid 用户id
     * @param x      关注数
     */
    @Transactional
    public void incFollowcount(String userid, Integer x) {
        userDao.incFollowcount(userid, x);
    }

    /**
     * 增加粉丝数
     *
     * @param userid
     * @param x
     */
    @Transactional
    public void incFanscount(String userid, Integer x) {
        userDao.incFanscount(userid, x);
    }

    /**
     * @param mobile
     * @param password
     * @return
     */
    public User findByMobileAndPassword(String mobile, String password) {
        User user = userDao.findByMobile(mobile);
        //使用filter判断两个密码是否是相等的
        return Optional.ofNullable(user)
                .filter(u -> encoder.matches(password, u.getPassword()))
                .orElse(null);
    }

    /**
     * 用户验证码注册
     *
     * @param user
     * @param code
     */
    public void add(User user, String code) {

        //判断验证码是否正确
        String syscode = String.valueOf(redisTemplate.opsForValue().get("smscode_" + user.getMobile()));
        if (syscode == null) {
            throw new RuntimeException("验证码已过期，请重新获取！");
        }
        if (!code.equals(syscode)) {
            throw new RuntimeException("验证码错误！");
        }
        // TODO 需要加上同一手机号不能重复注册的代码
        //验证手机号不能为空且不能是注册过得
//        String mobile = Optional.ofNullable(user).map(u -> u.getMobile())
//                .orElseThrow(() -> new RuntimeException("手机号不能为空！"));


//        Optional.ofNullable(userDao.findByMobile(mobile));

        //密码加密并且密码不能为空
        String newpassword = Optional.ofNullable(user)
                .map(u -> u.getPassword())
                .map(p -> encoder.encode(p))
                .orElseThrow(() -> new RuntimeException("密码不能为空"));
        user.setPassword(newpassword);

        user.setId(String.valueOf(idWorker.nextId()));
        user.setFollowcount(0);//关注数
        user.setFanscount(0);//粉丝数
        user.setOnline(0L);//在线时长
        Date time = Calendar.getInstance().getTime();
        user.setRegdate(time);//注册时间
        user.setUpdatedate(time);//更新日期
        user.setLastdate(time);//最后登录日期
        userDao.save(user);
    }

    /**
     * 发送手机验证码，一般是6位数
     *
     * @param mobile
     */
    public void sendSms(String mobile) {
        //生成100000~999999随机数
        int min = 100000, max = 999999;
        String code = String.valueOf(new Random().nextInt(max - min + 1) + min);
        System.out.println(mobile + "收到的验证码是：" + code);

        //将验证码放入redis并过期时间，yml中定义过期时间expiration-time
        redisTemplate.opsForValue().set("smscode_" + mobile, code, expirationTime, TimeUnit.MINUTES);

        //将验证码和手机号发动到rabbitMq中
        //这种方式生成的hasmMap，其实时HashMap的内部类，字节码反编译可以看到。
//        Map<String, String> map = new HashMap<>() {{
//            put("mobile", mobile);
//            put("code", code);
//        }};
        Map<String, String> map = new HashMap<>();
        map.put("mobile", mobile);
        map.put("code", code);

        rabbitTemplate.convertAndSend("sms", map);
    }

    /**
     * 查询全部列表
     *
     * @return
     */
    public List<User> findAll() {
        return userDao.findAll();
    }

    /**
     * 条件查询+分页
     *
     * @param whereMap
     * @param page
     * @param size
     * @return
     */
    public Page<User> findSearch(Map whereMap, int page, int size) {
        Specification<User> specification = createSpecification(whereMap);
        PageRequest pageRequest = PageRequest.of(page - 1, size);
        return userDao.findAll(specification, pageRequest);
    }


    /**
     * 条件查询
     *
     * @param whereMap
     * @return
     */
    public List<User> findSearch(Map whereMap) {
        Specification<User> specification = createSpecification(whereMap);
        return userDao.findAll(specification);
    }

    /**
     * 根据ID查询实体
     *
     * @param id
     * @return
     */
    public User findById(String id) {
        return userDao.findById(id).get();
    }

    /**
     * 增加
     *
     * @param user
     */
    public void add(User user) {
        user.setId(idWorker.nextId() + "");
        userDao.save(user);
    }

    /**
     * 修改
     *
     * @param user
     */
    public void update(User user) {
        userDao.save(user);
    }

    /**
     * 删除
     *
     * @param id
     */
    public void deleteById(String id) {
        userDao.deleteById(id);
    }

    /**
     * 动态条件构建
     *
     * @param searchMap
     * @return
     */
    private Specification<User> createSpecification(Map searchMap) {

        return new Specification<User>() {

            @Override
            public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                List<Predicate> predicateList = new ArrayList<Predicate>();
                // ID
                if (searchMap.get("id") != null && !"".equals(searchMap.get("id"))) {
                    predicateList.add(cb.like(root.get("id").as(String.class), "%" + (String) searchMap.get("id") + "%"));
                }
                // 手机号码
                if (searchMap.get("mobile") != null && !"".equals(searchMap.get("mobile"))) {
                    predicateList.add(cb.like(root.get("mobile").as(String.class), "%" + (String) searchMap.get("mobile") + "%"));
                }
                // 密码
                if (searchMap.get("password") != null && !"".equals(searchMap.get("password"))) {
                    predicateList.add(cb.like(root.get("password").as(String.class), "%" + (String) searchMap.get("password") + "%"));
                }
                // 昵称
                if (searchMap.get("nickname") != null && !"".equals(searchMap.get("nickname"))) {
                    predicateList.add(cb.like(root.get("nickname").as(String.class), "%" + (String) searchMap.get("nickname") + "%"));
                }
                // 性别
                if (searchMap.get("sex") != null && !"".equals(searchMap.get("sex"))) {
                    predicateList.add(cb.like(root.get("sex").as(String.class), "%" + (String) searchMap.get("sex") + "%"));
                }
                // 头像
                if (searchMap.get("avatar") != null && !"".equals(searchMap.get("avatar"))) {
                    predicateList.add(cb.like(root.get("avatar").as(String.class), "%" + (String) searchMap.get("avatar") + "%"));
                }
                // E-Mail
                if (searchMap.get("email") != null && !"".equals(searchMap.get("email"))) {
                    predicateList.add(cb.like(root.get("email").as(String.class), "%" + (String) searchMap.get("email") + "%"));
                }
                // 兴趣
                if (searchMap.get("interest") != null && !"".equals(searchMap.get("interest"))) {
                    predicateList.add(cb.like(root.get("interest").as(String.class), "%" + (String) searchMap.get("interest") + "%"));
                }
                // 个性
                if (searchMap.get("personality") != null && !"".equals(searchMap.get("personality"))) {
                    predicateList.add(cb.like(root.get("personality").as(String.class), "%" + (String) searchMap.get("personality") + "%"));
                }

                return cb.and(predicateList.toArray(new Predicate[predicateList.size()]));

            }
        };

    }

}
